import { NodeTypes } from "./ast";
import { TO_DISPLAY_STRING } from "./runtimeHelpers";

export function transform(root,options={}) {
    // 采用上下文的形式定义方法
    const context = createTransformContext(root, options);

    // 1.遍历 - 深度优先搜索;2.修改 text content（经优化后，由外部扩展进行修改）
    traverseNode(root,context)

    // root.codegenNode(使用codegen时就等同于root.children[0])
    createRootCodegen(root)

    // 将helpers赋值到根节点上
    root.helpers = [...context.helpers.keys()]
}

function createRootCodegen(root) {
    const child = root.children[0]
    if(child.type === NodeTypes.ELEMENT) {
        root.codegenNode = child.codegenNode
    } else {
        root.codegenNode = root.children[0]
    }
}
                                                                                                                           
function createTransformContext(root: any, options: any) {
    const context =  {
        root,
        nodeTransforms:options.nodeTransforms || [],
        helpers:new Map(),
        helper(key) {
            context.helpers.set(key,1)
        },
    }
    return context
}

function traverseNode(node: any, context: any) {
    const nodeTransforms = context.nodeTransforms
    const exitFns:any = []
    for (let i = 0; i < nodeTransforms.length; i++) {
        // transform 这个就是那个plugin函数
        const transform = nodeTransforms[i];
        const onExit = transform(node,context)
        if(onExit) exitFns.push(onExit)
    }

    switch (node.type) {
        case NodeTypes.INTERPOLATION:
            context.helper(TO_DISPLAY_STRING)
            break;
        case NodeTypes.ROOT:
        case NodeTypes.ELEMENT:
            // 递归处理children
            traverseChildren(node, context)
            break;
    
        default:
            break;
    }
    
    // 退出执行
    let i= exitFns.length
    while (i--) {
        exitFns[i]()
    }
}

function traverseChildren(node: any, context: any) {
    const children = node.children
    for (let i = 0; i < children.length; i++) {
        const node = children[i]
        traverseNode(node,context)
    }
}